#pragma once

#include "NodoSimple.h"
#include "NodoDoble.h"
#include "ListaDoble.h"
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

template <class T>
class ListaCircular
{ 
private:
    
    NodoDoble<T>* primero;  //puntero al inicio
    NodoDoble<T>* ultimo;
	NodoDoble<T>* actual;
	int cantidad;
	string flag;
public: 
	ListaCircular();
	ListaCircular(ListaCircular *);  //constructor copia
	virtual ~ListaCircular();

	string getFlag();
	void setFlag(string);
	NodoDoble<T>* getPrimero();
	NodoDoble<T>* getActual();
    NodoDoble<T>* getUltimo();
	void setActual(NodoDoble<T> *);
    void setPrimero(NodoDoble<T> *);
    void setUltimo(NodoDoble<T>*);
	void insertarUltimo(T*);
	void insertarPrimero(T *);
    void eliminarPos(int pos);
    void insertarPos(int pos, T*e);
    void intercambiar(int posA, int posB);
    
	//virtual int eliminar(string);		
	virtual string toString();
	virtual T * buscar(string);
	int getCantidad();
	void setCantidad(int);
    
};


template<class T>
string ListaCircular<T>::getFlag(){
   return flag;
}

template<class T>
void ListaCircular<T>::setFlag(string a){
	flag = a;
}


template<class T>
NodoDoble<T>* ListaCircular<T>::getActual(){
   return actual;
}

template<class T>
NodoDoble<T>* ListaCircular<T>::getUltimo(){
   return ultimo;
}



template<class T>
NodoDoble<T>* ListaCircular<T>::getPrimero(){
   return primero;


}

template<class T>
void ListaCircular<T>::setActual(NodoDoble<T> *act){

actual=act;
}

template<class T>
void ListaCircular<T>::setUltimo(NodoDoble<T> *act){
ultimo=act;
}


template<class T>
void ListaCircular<T>::setCantidad(int c){

cantidad = c;

}

template<class T>
void ListaCircular<T>::setPrimero(NodoDoble<T> *prim){

primero=prim;

}





template<class T>
ListaCircular<T>::ListaCircular()
{
	actual = primero = ultimo = NULL; 
	cantidad = 0;
}

template<class T>
ListaCircular<T>::ListaCircular(ListaCircular<T> *list)
{   
	
	list->setActual(list->getPrimero());
    if(list->getActual() != NULL)
    {
        insertarPrimero(new T(list->getActual()->getInfo()));
		list->setActual(list->getActual()->getSigNodo());
        
        while(list->getActual() != list->getPrimero())
        {
    		insertarPrimero(new T(list->getActual()->getInfo()));
        	list->setActual(list->getActual()->getSigNodo());
        }
    }
	
}


template<class T>
ListaCircular<T>::~ListaCircular()
{
    actual = primero;
	while(primero!=NULL)
	{
		actual = primero;
	    primero=primero->getSigNodo();
	    delete actual;
	}

}

template<class T>
void ListaCircular<T>::insertarPrimero(T * c)
{
	if(primero == NULL)
	{
		primero = new NodoDoble<T>(NULL,c, NULL);
        primero->setAntNodo(primero);
        primero->setSigNodo(primero);
        ultimo = primero;
	}
	else
	{
		actual = new NodoDoble<T>(ultimo,c,primero);
        ultimo->setSigNodo(actual);
        primero->setAntNodo(actual);
		primero = actual;
	}
	cantidad++;
}

template<class T>
void ListaCircular<T>::insertarUltimo(T * c)
{
	if(primero == NULL)
	{
		primero = new NodoDoble<T>(NULL,c, NULL);
        primero->setAntNodo(primero);
        primero->setSigNodo(primero);
        ultimo = primero;
	}
	else
	{
		actual = new NodoDoble<T>(ultimo,c, primero);
		ultimo->setSigNodo(actual);
        primero->setAntNodo(actual);
        ultimo = actual;
	}
	cantidad++;
}

//template<class T>
//int ListaCircular<T>::eliminar(string codigo){
//	
//	int ret = 0;
//	if(primero!=NULL)
//	{
//	    actual = primero;
//		if(*(primero->getInfo())== codigo)
//		{
//			primero=primero->getSigNodo();
//            primero->setAntNodo(ultimo);
//            ultimo->setSigNodo(primero);
//			delete actual;
//			cantidad--;
//            return ret = 1;
//		}
//		else
//		{
//
//			NodoDoble<T> *aux;
//			while(actual->getSigNodo()!=primero)
//			{   
//				if(*(actual->getSigNodo()->getInfo())==codigo)
//				{
//					aux=actual->getSigNodo();
//					actual->setSigNodo(actual->getSigNodo()->getSigNodo());
//                    actual->getSigNodo()->getSigNodo()->setAntNodo(actual);
//					delete aux;
//					cantidad--;
//					return ret = 1;
//				}
//				actual=actual->getSigNodo();
//			}
//		}
//	}
//	return ret;
//}

template<class T>
string ListaCircular<T>::toString()
{
	stringstream s; 
    if(primero==NULL)
    	s<<"\tLa lista esta vacia";

    else
    {
        int i=1;
        s<<"\t["<<i++<<"]-------------------- \n";
		s<< "\t"<<primero->getInfo()->toString()<<endl;
    	actual = primero->getSigNodo();
        
    	while(actual != primero)
    	{
    		s<<"\t["<<i++<<"]-------------------- \n";
			s<< "\t"<<actual->getInfo()->toString()<<endl;
    		actual = actual->getSigNodo();
    	}
    }
    return s.str();
}

template<class T>
T* ListaCircular<T>::buscar(string codigo){

 actual=primero;
 if(actual != NULL)
 {
    if(*(actual->getInfo())==codigo)
	{
		return (actual->getInfo());
	}
    actual = actual->getSigNodo();
	while(actual!=primero)
	{
		if(*(actual->getInfo())==codigo)
		{
			return (actual->getInfo());
		}

		actual=actual->getSigNodo();
	}
 }
	return NULL;
}

template<class T>
int ListaCircular<T>::getCantidad()
{
	return cantidad;
}

template<class T>
void ListaCircular<T>::insertarPos(int pos, T* e) //comienza en 0
{

    if(pos==cantidad+1)
    {
        this->insertarUltimo(e);
    }
    else if(pos==1)
    {
        this->insertarPrimero(e);
    }
    else
    {
        actual = primero;
        for(int i=1;i<pos;i++)
        {
            actual = actual->getSigNodo();
        }
        NodoDoble<T>* aux = new NodoDoble<T>(NULL, e, actual);
        
        if(actual->getAntNodo()!=NULL)
        {
            aux->setAntNodo(actual->getAntNodo());
            actual->getAntNodo()->setSigNodo(aux);
        }
        actual->setAntNodo(aux);
    }
}


template<class T>
void ListaCircular<T>::eliminarPos(int pos)
{
    if(primero != NULL)
    {
        actual = primero;
        if(pos==1)
        {
            NodoDoble<T>* aux = actual;
            primero = primero->getSigNodo();
            ultimo->setSigNodo(primero);
            primero->setAntNodo(ultimo);
            delete aux;
            cantidad --;        
        }
        else if(pos == cantidad)
        {
            NodoDoble<T>* aux = ultimo;
            ultimo = ultimo->getAntNodo(); //anterior del ultimo
            ultimo->setSigNodo(primero);
            primero->setAntNodo(ultimo);
            delete aux;
            cantidad --;                
        }
        else
        {
            for(int i=1;i<pos;i++)
            {
                actual = actual->getSigNodo();
            }
           
            if(actual->getAntNodo() != NULL)
            {
                actual->getAntNodo()->setSigNodo(actual->getSigNodo());
            }
            if(actual->getSigNodo()!=NULL)
            {
                actual->getSigNodo()->setAntNodo(actual->getAntNodo());
            }
            delete actual;
            cantidad --;
    
        }
    }
}

template<class T>
void ListaCircular<T>::intercambiar(int posA, int posB)//intrcambiar posA con posB
{
    if(primero != NULL && primero->getSigNodo() != primero)
    {
       
        actual = primero;
        for(int i=1;i<posA;i++)
        {
            actual = actual->getSigNodo();
        }
        NodoDoble<T>* A = actual;

        actual = primero;
        for(int i=1;i<posB;i++)
        {
            actual = actual->getSigNodo();
        }
        NodoDoble<T>* B = actual;

        T* aux = A->getInfo(); 
        A->setInfo(B->getInfo());
        B->setInfo(aux);
    }
}
